package com.sum.tea.rongrui.viewmodel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ConvertUtils
import com.example.lib_rongrui.RrReader
import com.rfid.trans.MaskClass
import com.rfid.trans.ReadTag
import com.rfid.trans.TagCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.HashMap
import kotlin.collections.List
import kotlin.collections.MutableList
import kotlin.collections.hashMapOf
import kotlin.collections.indexOf
import kotlin.collections.isNotEmpty
import kotlin.collections.map
import kotlin.collections.mutableListOf
import kotlin.collections.set
import kotlin.collections.toMutableList

class ScanModeViewModel(application: Application) : AndroidViewModel(application) {

    // LiveData for updating UI
    private val _tagList = MutableLiveData<MutableList<HashMap<String, String>>>()
    val tagList: LiveData<MutableList<HashMap<String, String>>> get() = _tagList

    private val _count = MutableLiveData<String>("0")
    val count: LiveData<String> get() = _count

    private val _time = MutableLiveData<String>("00:00:00")
    val time: LiveData<String> get() = _time

    private val _allTag = MutableLiveData<String>("0")
    val allTag: LiveData<String> get() = _allTag

    private val _speed = MutableLiveData<String>("0")
    val speed: LiveData<String> get() = _speed

    private val _isInventorying = MutableLiveData<Boolean>(false)
    val isInventorying: LiveData<Boolean> get() = _isInventorying

    // Other necessary variables
    public var inventoryFlag: Int = 1
    public var isStopThread: Boolean = false
    private val mlist = mutableListOf<String>()
    private var CardNumber: Long = 0
    private var beginTime: Long = 0
    private var lastTime: Long = 0
    private var lastCount: Int = 0
    private var runtime: Int = 0
    public var keyPress: Boolean = false

    // Using a thread-safe map to store tags
    private val tagMap = ConcurrentHashMap<String, HashMap<String, String>>()

    private val callback = object : TagCallback {
        override fun tagCallback(arg0: ReadTag) {
            val epc = arg0.epcId?.toUpperCase() ?: ""
            val mem = arg0.memId?.toUpperCase() ?: ""
            val rssi = arg0.rssi.toString()
            viewModelScope.launch {
                handleTagCallback(epc, mem, rssi)
            }
        }

        override fun StopReadCallBack() {
            viewModelScope.launch {
                _isInventorying.value = false
                // Handle stop inventory
            }
        }
    }

    init {
        _tagList.value = mutableListOf()
        RrReader.rrlib.SetCallBack(callback)
    }

    // Callback implementation

    private suspend fun handleTagCallback(epc: String, mem: String, rssi: String) {
        withContext(Dispatchers.Main) {
            val tag = if (mem.isEmpty()) "$epc,$rssi" else "$epc,$mem,$rssi"
            addEPCToList(epc, mem, rssi)
            // Update speed if necessary
            val currentTime = System.currentTimeMillis()
            if (currentTime - lastTime >= 1000) {
                _speed.value = ((lastCount * 1000) / (currentTime - lastTime)).toString()
                lastTime = currentTime
                lastCount = 0
            }
            lastCount++
        }
    }

    private fun addEPCToList(epc: String, mem: String, rssi: String) {
        if (epc.isNotEmpty()) {
            val fullEpc = if (mem.isEmpty()) epc else "EPC:$epc\r\nMem:$mem"
            if (tagMap.containsKey(fullEpc)) {
                val existingTag = tagMap[fullEpc]
                existingTag?.let {
                    val count = it["tagCount"]?.toIntOrNull()?.plus(1) ?: 1
                    it["tagCount"] = count.toString()
                }
            } else {
                val map = hashMapOf<String, String>(
                    "tagUii" to fullEpc,
                    "tagCount" to "1",
                    "tagRssi" to rssi
                )
                tagMap[fullEpc] = map
                mlist.add(epc)
                CardNumber++
            }
            _tagList.value = tagMap.values.toMutableList()
            _count.value = tagMap.size.toString()
            _allTag.value = CardNumber.toString()
        }
    }

    fun clearData() {
        _count.value = "0"
        _time.value = "00:00:00"
        _allTag.value = "0"
        _speed.value = "0"
        tagMap.clear()
        mlist.clear()
        CardNumber = 0
        _tagList.value = tagMap.values.toMutableList()
    }

    fun checkIsExist(strEPC: String?): Int {
        strEPC ?: return -1
        return tagMap.keys.indexOf(strEPC)
    }

    fun startInventory(inventoryFlag: Int, ledList: List<String>?, factoryPosition: Int) {
        this.inventoryFlag = inventoryFlag
        viewModelScope.launch {
            if (_isInventorying.value == true) return@launch
            _isInventorying.value = true
            when (inventoryFlag) {
                0 -> { // 单步
                    RrReader.rrlib.ScanRfid()
                }
                1 -> { // 循环
                    val result = if (ledList != null && ledList.isNotEmpty()) {
                        val maskList = ledList.map { led ->
                            MaskClass().apply {
                                MaskAdr[0] = 0
                                MaskAdr[1] = 0x20
                                MaskMem = 1
                                MaskLen = (led.length * 4).toByte()
                                MaskData = ConvertUtils.hexString2Bytes(led)
                            }
                        }
                        RrReader.rrlib.StartInventoryLed(factoryPosition, maskList)
                    } else {
                        RrReader.rrlib.StartRead()
                    }
                    if (result == 0) {
                        beginTime = System.currentTimeMillis()
                        lastTime = beginTime
                        lastCount = 0
                        // Start coroutine to update time
                        viewModelScope.launch {
                            while (_isInventorying.value == true) {
                                val elapsed = System.currentTimeMillis() - beginTime
                                val hours = elapsed / (60 * 60 * 1000)
                                val minutes = (elapsed / 1000 % 3600) / 60
                                val seconds = (elapsed / 1000 % 60)
                                _time.value = String.format("%02d:%02d:%02d", hours, minutes, seconds)
                                if (runtime != 0 && elapsed > runtime * 1000) {
                                    stopInventory()
                                }
                                kotlinx.coroutines.delay(200)
                            }
                        }
                    }
                }
                else -> {}
            }
        }
    }

    fun stopInventory() {
        viewModelScope.launch {
            if (_isInventorying.value == false) return@launch
            if (inventoryFlag == 1) {
                RrReader.rrlib.StopInventoryLed()
            } else {
                RrReader.rrlib.StopRead()
            }
            _isInventorying.value = false
        }
    }
}
